Skip to content

Fix(Replay): dont record ignored/dropped errors#5885

Merged
lucas-zimerman merged 11 commits intomainfrom
lz/ignore-replay
Mar 26, 2026
Merged

Fix(Replay): dont record ignored/dropped errors#5885
lucas-zimerman merged 11 commits intomainfrom
lz/ignore-replay

Conversation

@lucas-zimerman
Copy link
Collaborator

@lucas-zimerman lucas-zimerman commented Mar 25, 2026

📢 Type of change

  • Bugfix
  • New feature
  • Enhancement
  • Refactoring

📜 Description

Users wanted to only track errors, but the way mobileReplay was set, it triggered replay captured even to dropped errors, since it was doing this on the middle of the event processing workflow, which could lead to dropped events before sending it.

💡 Motivation and Context

The fix is a hook into beforeSend, since it's the last stop before sending an event.
Ideally we shold use something like client.on('beforeBeforeSend... but the client hook was syncronous, which blocks the usage of Native APIs to fetch the replay data to fill into the event's context.

This way, when users set to only capture errors, Replay will not send recording data when the only captured events were dropped by IgnoredError/eventProcessor or beforeSend.

💚 How did you test it?

On a device, sample app.

📝 Checklist

  • I added tests to verify changes
  • No new PII added or SDK only sends newly added PII if sendDefaultPII is enabled
  • I updated the docs if needed.
  • I updated the wizard if needed.
  • All tests passing
  • No breaking changes

🔮 Next steps

Close #4908

@github-actions
Copy link
Contributor

github-actions bot commented Mar 25, 2026

Semver Impact of This PR

None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


  • Fix(Replay): dont record ignored/dropped errors by lucas-zimerman in #5885
  • fix(android): Capture native exceptions consumed by Expo's bridgeless error handling by alwx in #5871
  • chore(core): Upgrade TypeScript from 4.9.5 to 5.9.3 by antonis in #5886
  • chore(deps): update JavaScript SDK to v10.46.0 by github-actions in #5890
  • chore(deps): update CLI to v3.3.4 by github-actions in #5891
  • chore(deps): bump picomatch from 2.3.1 to 2.3.2 by dependabot in #5889
  • fix(core): Fix stale deprecation references by antonis in #5881
  • chore(build): Rename version-bump.js to bump-version.js by antonis in #5883
  • chore(deps): bump activesupport from 7.0.8.6 to 7.2.3.1 in /samples/react-native-macos by dependabot in #5870
  • chore(deps): bump activesupport from 6.1.7.10 to 7.2.3.1 in /samples/react-native by dependabot in #5869
  • chore(deps): bump yauzl to ^3.2.1 by antonis in #5855
  • chore(deps): bump appium from 2.4.1 to 3.2.2 by antonis in #5856
  • fix(ios): Guard replay postInit behind runtime session replay check by antonis in #5858
  • Add better needs_web check to CI by alwx in #5863
  • chore(deps): bump fast-xml-parser to ^5.5.7 by antonis in #5854
  • CI: detect-changes workflow to only check the affected components on the CI side by alwx in #5843
  • chore(deps): bump getsentry/craft/.github/workflows/changelog-preview.yml from 2.24.1 to 2.25.0 by dependabot in #5861
  • chore(deps): bump getsentry/craft from 2.24.1 to 2.25.0 by dependabot in #5862
  • chore(deps): bump github/codeql-action from 4.32.6 to 4.34.1 by dependabot in #5860
  • chore(deps): update JavaScript SDK to v10.45.0 by github-actions in #5848
  • chore(deps): bump flatted from 3.4.1 to 3.4.2 by dependabot in #5853
  • chore(deps): update Cocoa SDK to v9.8.0 by github-actions in #5847
  • fix(tracing): Guard getNewScreenTimeToDisplay behind enableTimeToInitialDisplay by antonis in #5849
  • chore(deps): bump json from 2.16.0 to 2.17.1.2 in /performance-tests by dependabot in #5844

Plus 4 more


🤖 This preview updates automatically when you update the PR.

@lucas-zimerman lucas-zimerman marked this pull request as ready for review March 25, 2026 14:58
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Replay bridge errors can drop events
    • Added try-catch around processEvent in beforeSend to ensure events are sent without replay data when native bridge calls fail, rather than being dropped.

Create PR

Or push these changes by commenting:

@cursor push 6824446734
Preview (6824446734)
diff --git a/packages/core/src/js/replay/mobilereplay.ts b/packages/core/src/js/replay/mobilereplay.ts
--- a/packages/core/src/js/replay/mobilereplay.ts
+++ b/packages/core/src/js/replay/mobilereplay.ts
@@ -308,15 +308,21 @@
     const clientOptions = client.getOptions();
     const originalBeforeSend = clientOptions.beforeSend;
     clientOptions.beforeSend = async (event: ErrorEvent, hint: EventHint): Promise<ErrorEvent | null> => {
+      let eventToProcess = event;
       if (originalBeforeSend) {
         const result = await originalBeforeSend(event, hint);
         if (result === null) {
           // Event was dropped by user's beforeSend, don't capture replay
           return null;
         }
-        return processEvent(result, hint);
+        eventToProcess = result;
       }
-      return processEvent(event, hint);
+      try {
+        return await processEvent(eventToProcess, hint);
+      } catch (error) {
+        debug.error(`[Sentry] ${MOBILE_REPLAY_INTEGRATION_NAME} failed to process event, sending without replay data`, error);
+        return eventToProcess;
+      }
     };
   }
 

diff --git a/packages/core/test/replay/mobilereplay.test.ts b/packages/core/test/replay/mobilereplay.test.ts
--- a/packages/core/test/replay/mobilereplay.test.ts
+++ b/packages/core/test/replay/mobilereplay.test.ts
@@ -143,6 +143,57 @@
       expect(mockCaptureReplay).not.toHaveBeenCalled();
       expect(result?.contexts?.replay).toBeUndefined();
     });
+
+    it('should return event unchanged when native bridge call fails', async () => {
+      mockCaptureReplay.mockRejectedValue(new Error('Native bridge error'));
+
+      const integration = mobileReplayIntegration();
+      integration.setup?.(mockClient);
+
+      const event = {
+        event_id: 'test-event-id',
+        exception: {
+          values: [{ type: 'Error', value: 'Test error' }],
+        },
+      } as ErrorEvent;
+      const hint: EventHint = {};
+
+      const result = await clientOptions.beforeSend?.(event, hint);
+
+      expect(result).toBeDefined();
+      expect(result).toBe(event);
+      expect(result?.contexts?.replay).toBeUndefined();
+    });
+
+    it('should return modified event from user beforeSend when native bridge fails', async () => {
+      mockCaptureReplay.mockRejectedValue(new Error('Native bridge error'));
+
+      const userBeforeSend = jest
+        .fn<(event: ErrorEvent, hint: EventHint) => ErrorEvent>()
+        .mockImplementation(event => ({
+          ...event,
+          tags: { modified: 'true' },
+        }));
+      clientOptions.beforeSend = userBeforeSend;
+
+      const integration = mobileReplayIntegration();
+      integration.setup?.(mockClient);
+
+      const event = {
+        event_id: 'test-event-id',
+        exception: {
+          values: [{ type: 'Error', value: 'Test error' }],
+        },
+      } as ErrorEvent;
+      const hint: EventHint = {};
+
+      const result = await clientOptions.beforeSend?.(event, hint);
+
+      expect(result).toBeDefined();
+      expect(userBeforeSend).toHaveBeenCalledWith(event, hint);
+      expect(result?.tags).toEqual({ modified: 'true' });
+      expect(result?.contexts?.replay).toBeUndefined();
+    });
   });
 
   describe('beforeErrorSampling', () => {

This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Copy link
Contributor

@antonis antonis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 🚀
It would be nice to add the try/catch cursor suggests and run the full test suite.

lucas-zimerman and others added 2 commits March 26, 2026 10:48
@lucas-zimerman lucas-zimerman added the ready-to-merge Triggers the full CI test suite label Mar 26, 2026
@lucas-zimerman
Copy link
Collaborator Author

LGTM 🚀 It would be nice to add the try/catch cursor suggests and run the full test suite.

Done on aac5968

@lucas-zimerman lucas-zimerman merged commit d5a0c04 into main Mar 26, 2026
53 of 75 checks passed
@lucas-zimerman lucas-zimerman deleted the lz/ignore-replay branch March 26, 2026 11:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-to-merge Triggers the full CI test suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Sentry Replays counting muted Errors or something off

2 participants